Lang.define ('Bs.ui');
var D = document;
Lang.copy (Device, {
	ID_PREFIX: 'bse-',
	cnt: 0,
	id : function (he) {
		return he.id ? he.id : (Device.ID_PREFIX + (++this.cnt));
	},
	he: function (he) {
		if(!he){
			return null;
		}
		return Lang.isString (he) ? D.getElementById (he) : he;
	}, 
	create: function (he) {
		return new Bs.ui.Component (he, {paint: false});
	}
});
Bs.ui.Component = function (props) {
	Bs.ui.Component.superclass.constructor.call (this, props);
	this.painted = false;
	this.he = Device.he (this.he);
	if (this.init) {
		this.init ();
	}
	if (Sys.Cache && this.he && this.he.id && Sys.Cache.get (this.he.id)) {
		return Sys.Cache.get (this.he.id);
	}
	this.setId ();
	if (Sys.Cache && this.isCachable ()) {
		return Sys.Cache.put (this.id, this);
	}
	if ((this.processPaint == undefined || this.processPaint) && this.paint) {
		this.paint ();
	}
};

Lang.extend (Bs.ui.Component, Bs.lang.Object, {
	spec: Html.DIV,
	clsReCache: {},
	paint : function () {
		if(this.doPaint () === false) {
			return;
		}
		this.painted = true;
	},
	doPaint : function () {
		if (!this.spec) {
			this.spec = Html.DIV;
		}
		var created;
		if (Lang.isString (this.spec)){
			created = D.createElement (this.spec);
		} else {
			var div = D.createElement (Html.DIV);
			Html.overwrite (div, this.spec);
			created = div.firstChild;
		}
		created.id = Device.id (created);
		if (this.he) {
			this.he.appendChild (created);
		} else {
			this.he = created;
			(D.body || D.documentElement).appendChild (this.he);
		}
		this.addCls (this.cls);
		return true;
	},
	isCachable : function () {
		return this.cachable || this.cachable == undefined || !Lang.isBoolean ();
	},
	erase : function () {
		
	},
	renew : function (he, repaint, clean) {
		if (clean) {
			this.erase ();
		}
		he = Device.he (he);
		if (!he) {
			if (repaint && (this.processPaint == undefined || this.processPaint) && this.paint) {
				this.paint ();
			}
			return;
		}
		this.he = he;
		this.setId ();
		if (repaint && (this.processPaint == undefined || this.processPaint) && this.paint) {
			this.paint ();
		}
	},
	setId : function () {
		if (!this.he || this.he == D.body) {
			return;
		}
		this.id = Device.id (this.he);
		if (!this.he.id) {
			this.he.id = this.id;
		}
	}, 
	addCls : function (cls){
		if (!cls) {
			return this;
		}
		var cmp = this;
		Lang.loop (cls, function (x) {
			cmp.he.className += (!cmp.hasCls(x) && x ? Strings.SPACE + x : Strings.EMPTY);  
		});
		return cmp;
	},
	removeCls : function(cls){
		if (!cls) {
			return this;
		}
		var cmp = this;
		if (cmp.he.className) {
			Lang.loop (cls, function(x) {               
				cmp.he.className = cmp.he.className.replace(
					clsReCache[x] = clsReCache[x] || new RegExp('(?:^|\\s+)' + x + '(?:\\s+|$)', "g"), 
			        Strings.SPACE);               
			});    
		}
		return cmp;
	},
	hasCls : function (cls){
		if (!cls) {
			return false;
		}
		return cls && (Strings.SPACE + this.he.className + Strings.SPACE).indexOf(Strings.SPACE + cls + Strings.SPACE) != -1;
	},
	switchCls : function (oldCls, newCls){
		if (!newCls) {
			return this.removeCls (oldCls);
		}
		if (!oldCls) {
			return this.addCls (oldCls);
		}
		return this.removeCls (oldCls).addCls (newCls);
	},
    getXY : function(){
        return D.getXY (this.he);
    }
});

Lang.copy (Device, {
	getBody : function () {
		return Device.create (D.body || D.documentElement);
	},
	widgets: {"Component": Bs.ui.Component},
	getWidget: function (o) {
		var w = o.widget;
		if (!w) {
			return new Bs.ui.Component (o);
		}
		var clz = Device.widgets[w];
		if (!clz) {
			return new Bs.ui.Component (o);
		}
		return new clz (o);
	},
	addWidget: function (name, clazz) {
		if (!Device.widgets) {
			Device.widgets = {};
		}
		Device.widgets[name] = clazz;
	},
	ready : false,
	onReady: function (fn) {
		if (Device.ready) {
			return fn();
		}
		var observers = Device.observers;
		if (!observers) {
			observers = Device.observers = [];
		}
		observers[observers.length] = fn;
		if (Device.loadingCallback) {
			return;
		}
		Device.loadingCallback = function() {
			if (Device.ready) {
				return;
			}
			Device.ready = true;
			if (Device.loadingTimer) {
				clearInterval (Device.loadingTimer);
				Device.loadingTimer = null;
			}
			var observers = Device.observers;
			for (var i = 0, length = observers.length; i < length; i++) {
				var fn = observers[i];
				observers[i] = null;
				fn();
			}
			Device.loadingCallback = Device.observers = null;
		};
    
		// -----------------------------------------------------------
		// Emulates 'onDOMContentLoaded'
		// -----------------------------------------------------------
		if (document.readyState && Sys.isWebKit) {
			// Apple WebKit (Safari, OmniWeb, ...)
			Device.loadingTimer = setInterval (function() {
				var state = document.readyState;
				if (state == 'loaded' || state == 'complete') {
					Device.loadingCallback();
				}
			}, 50);
		} else if (document.readyState && Sys.isIE) {
			// Windows IE
			var src = Sys.isSecure ? '://0' : 'javascript:void(0)';
			document.write(
				'<script type="text/javascript" defer="defer" src="' + src + '" ' + 
				'onreadystatechange="if (this.readyState == \'complete\') Device.loadingCallback();"' + 
				'><\/script>');
		} else {
			if (window.addEventListener) {
				// for Mozilla browsers, Opera 9
				document.addEventListener("DOMContentLoaded", Device.loadingCallback, false);
				// Fail safe
				window.addEventListener("load", Device.loadingCallback, false);
			} else if (window.attachEvent) {
				window.attachEvent('onload', Device.loadingCallback);
			} else {
				// Legacy browsers (e.g. Mac IE 5)
				var fn = window.onload;
				window.onload = function() {
					Device.loadingCallback ();
					if (fn) {
						fn();
					}
				}
			}
		}
	}
});